package com.liruo.enumconverter.nogeneric.deserialize;

import com.liruo.enumconverter.model.SourceEnum;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;

import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author:liruo
 * @Date:2023-02-19-13:46:59
 * @Desc
 * 注意传参是class要对应Converter的第二个泛型，这个实在没办法用泛型规范
 * 必须指定什么类型由什么类型来转换 即不能泛型化--参数化
 */
public abstract class AbstractSourceToEnumConverterFactory<S> implements ConverterFactory<S, SourceEnum<S>>{
    private final ConcurrentHashMap<Integer, SourceToEnumConverter<S, ? extends SourceEnum<S>>> cache;
    private final Object lock = new Object();
    protected final Class<S> sourceClazz;
    public AbstractSourceToEnumConverterFactory(Class<S> sourceClazz) {
        this.sourceClazz = sourceClazz;
        this.cache = new ConcurrentHashMap<>();
    }


    @SuppressWarnings("unchecked")
    protected  <T extends SourceEnum<S>> Converter<S, T> getConverterBySource(Class<T> targetType) {
        int hashCode = targetType.getName().hashCode();
        SourceToEnumConverter<S, ? extends SourceEnum<S>> sourceToEnumConverter = this.cache.get(hashCode);
        if(sourceToEnumConverter == null){
            synchronized (this.lock){
                sourceToEnumConverter = this.cache.get(hashCode);
                if(sourceToEnumConverter == null){
                    Class<?> sourceClass = targetType.getEnumConstants()[0].source().getClass();
                    if(sourceClass != this.sourceClazz){
                        throw new IllegalArgumentException("require sourceClass is " + this.sourceClazz.getName()
                                + ", but provide enum " + targetType.getName() + "'s sourceClass is " + sourceClass.getName());
                    }
                    sourceToEnumConverter = new SourceToEnumConverter<>(targetType);
                    this.cache.put(hashCode, sourceToEnumConverter);
                }
            }
        }
        return (Converter<S, T>) sourceToEnumConverter;
    }

    private static class ClassKey{
        private Integer hashcode;

    }
}
